﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections.ObjectModel;
using System.IO;
using Kokomo.Environment.Services;
using Kokomo.Environment.Commanding;

namespace Kokomo.Environment.Hosting.Services
{
	class DocumentManager : ServiceObjectBase, IDocumentManager
	{
		public DocumentManager(EditorApplication editorApplication)
			: base(editorApplication)
		{
			this._documentViewModels = new ObservableCollection<DocumentViewModel>();
		}

		private ObservableCollection<DocumentViewModel> _documentViewModels;
		public IEnumerable<DocumentViewModel> DocumentViewModels { get { return this._documentViewModels; } }

		public DocumentViewModel FindOpenDocumentForPath(string path)
		{
			if (path == null) throw new ArgumentNullException("path");

			DocumentViewModel matchDocumentViewModel = null;
			foreach (var document in this.DocumentViewModels)
			{
				if (document.FileName == path)
				{
					matchDocumentViewModel = document;
					break;
				}
			}

			return matchDocumentViewModel;
		}

		public DocumentViewModel OpenDocumentFromFile(string fileName)
		{
			if (fileName == null) throw new ArgumentNullException("fileName");

			string fullPath = Path.GetFullPath(fileName);
			{
				DocumentViewModel openDocumentViewModel = this.FindOpenDocumentForPath(fullPath);
				if (openDocumentViewModel != null)
				{
					this.ShowDocument(openDocumentViewModel);
					return openDocumentViewModel;
				}
			}

			DocumentEditor editor = this.EditorApplication.DetermineEditor(fileName);
			if (editor == null) throw new InvalidOperationException(Messages.NoRegisteredEditorMessage);

			DocumentViewModel documentViewModel = editor.OpenExisting(fileName);
			if (documentViewModel != null)
			{
				// Create and add view model
				documentViewModel.FileName = fileName;
				ShowDocument(documentViewModel);
			}

			return documentViewModel;
		}

		public void ShowDocument(DocumentViewModel documentViewModel)
		{
			if (documentViewModel == null) throw new ArgumentNullException("documentViewModel");

			if (!this._documentViewModels.Contains(documentViewModel))
			{
				this._documentViewModels.Add(documentViewModel);
				documentViewModel.Closing += new EventHandler(documentViewModel_Closing);
			}

			this.ActiveDocumentViewModel = documentViewModel;
		}

		void documentViewModel_Closing(object sender, EventArgs e)
		{
			this._documentViewModels.Remove(((DocumentViewModel)sender));
		}

		private DocumentViewModel _activeDocumentViewModel;
		public DocumentViewModel ActiveDocumentViewModel
		{
			get { return this._activeDocumentViewModel; }
			set
			{
				this._activeDocumentViewModel = value;
				this.OnActiveDocumentChanged();
			}
		}

		public event EventHandler ActiveDocumentChanged;
		protected virtual void OnActiveDocumentChanged()
		{
			if (this.ActiveDocumentChanged != null) this.ActiveDocumentChanged(this, EventArgs.Empty);
			this.OnPropertyChanged("ActiveDocumentViewModel");
		}

		public ErrorDocumentViewModel CreateErrorDocumentViewModel(
			UiString mainCaption,
			UiString detail,
			Exception exception = null,
			string documentFileName = null
			)
		{
			ErrorDocumentViewModel errorDocumentViewModel = new ErrorDocumentViewModel()
			{
				MainCaption = mainCaption,
				Detail = detail,
				FileName = documentFileName,
				Exception = exception
			};

			if (documentFileName != null)
			{
				errorDocumentViewModel.CommandViewModels.Add(this.CreateRetryDocumentCommandViewModel(errorDocumentViewModel));
			}

			return errorDocumentViewModel;
		}
		public ErrorDocumentViewModel CreateAndShowErrorDocumentViewModel(
			UiString mainCaption,
			UiString detail,
			Exception exception = null,
			string documentFileName = null
			)
		{
			ErrorDocumentViewModel errorDocumentViewModel = this.CreateErrorDocumentViewModel(mainCaption, detail, exception, documentFileName);
			this.EditorApplication.DocumentManager.ShowDocument(errorDocumentViewModel);

			return errorDocumentViewModel;
		}

		private CommandViewModel CreateRetryDocumentCommandViewModel(DocumentViewModel documentViewModel)
		{
			if (documentViewModel == null) throw new ArgumentNullException("documentViewModel");

			return new CommandViewModel(new ParameterizedCommand(this.RetryOpenDocument), UiString.FromString(Messages.RetryOpenDocumentCommandText))
			{
				Argument = documentViewModel
			};
		}

		private void RetryOpenDocument(object arg)
		{
			DocumentViewModel documentViewModel = arg as DocumentViewModel;
			if (documentViewModel == null) return;

			string fileName = documentViewModel.FileName;
			documentViewModel.Close();
			this.EditorApplication.OpenDocumentFromFile(fileName);
		}
	}
}
